/*
作者：747929791、sth
这是默认人机对战AI
通过向播放器文件中的ActionIcons目录添加图片可以在游戏中添加自定义按钮
*/

#include "sdk/sdk.h"
#include "sdk/misc.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <map>

using Pos = SDK::Pos;
using PPlayerInfo = SDK::PPlayerInfo;
using PCommand = SDK::PCommand;
using PShowInfo = SDK::PShowInfo;
using Edge = PPlayerInfo::Edge;
using Robot = PPlayerInfo::Robot;
using HumanOrder = PPlayerInfo::HumanOrder;
using Buff = Robot::Buff;
using Skill = Robot::Skill;
using Operation = PCommand::Operation;
using ShowInfo = PShowInfo::ShowInfo;

PPlayerInfo playerInfo;
PCommand pCommand;
PShowInfo *pShowInfo;

std::map <string, string> last_target;

//人工操作解析器
class Parser
{
private:
    Pos source;//技能发起者
    Pos choose;//当前选择的机器人
    bool uTargetSkill;//是否处于释放单目标点技能状态
    OrderType type;//当前使用的技能类型
public:
    bool isFeedBack;//是否为反馈解释器(非反馈解释器不ShowInfo)
    Parser()
    {
        uTargetSkill=false;
        source=Pos(-1,-1);
    }

    void Select(Pos target)
    {
        choose = target;
        if(isFeedBack)pShowInfo->SelectGrid(target);
    }

    void Deselect()
    {
        choose = Pos(-1,-1);
        if(isFeedBack)pShowInfo->DeselectGrid();
    }

    //这个解析器会将所有人工操作显示在播放器的控制台中
    void log(const HumanOrder& order)
    {
        switch (order.type)
        {
            case HumanOrderType::Console: pShowInfo->ShowString("Console:"+order.info);break;
            case HumanOrderType::KeyDown: pShowInfo->ShowString(string("KeyDown id:") + to_string(order.id) + " name:"+order.info);break;
            case HumanOrderType::KeyUp: pShowInfo->ShowString(string("KeyUp id:") + to_string(order.id) + " name:"+order.info);break;
            case HumanOrderType::LeftMouseDown: pShowInfo->ShowString(string("LeftMouseDown:") + order.target.ToString());break;
            case HumanOrderType::LeftMouseUp: pShowInfo->ShowString(string("LeftMouseUp:") + order.target.ToString());break;
            case HumanOrderType::LeftMouseClick: pShowInfo->ShowString(string("LeftMouseClick:") + order.target.ToString());break;
            case HumanOrderType::RightMouseClick: pShowInfo->ShowString(string("RightMouseClick:") + order.target.ToString());break;
            case HumanOrderType::LocalButtonClick: pShowInfo->ShowString(string("LocalButtonClick id:") + to_string(order.id) + " name:"+order.info);break;
            case HumanOrderType::GlobalButtonClick: pShowInfo->ShowString(string("GlobalButtonClick id:") + to_string(order.id) + " name:"+order.info);break;
        }
    }

    //解析按下局部按钮的事件
    void parseLocalButtonClick(const HumanOrder& order)
    {
        source=order.target;
        if (!isFeedBack && playerInfo.RobotAt(source) == nullptr) return;
        switch (order.id)
        {
            /* 这一段将会标记当前所执行的操作类型 */
            case 0: type = OrderType::PlainAttack;uTargetSkill=true;break;
            case 1: type = OrderType::Split;uTargetSkill=true;break;
            case 2: type = OrderType::Connect;uTargetSkill=true;break;
            case 3: type = OrderType::Disconnect;uTargetSkill=true;break;
            case 4: type = OrderType::Recover;uTargetSkill=true;break;
            case 5: type = OrderType::Airborne;uTargetSkill=true;break;
            case 6: pCommand.AddOrder(OrderType::Overload,source);break;
            case 7: type = OrderType::Scourge;uTargetSkill=true;break;
            case 8: type = OrderType::Bombing;uTargetSkill=true;break;
            case 9: pCommand.AddOrder(OrderType::Shielding,source);break;
            case 16: type = OrderType::Evolve;break;
            case 17: type = OrderType::Vestigial;break;
                /* 这一段操作将会完成升降级的操作流程 */
            default:
                if(type == OrderType::Evolve || type == OrderType::Vestigial)
                    switch(order.id){
                        case 48: pCommand.AddOrder(type,source,RobotType::RawRobot);break;
                        case 50: pCommand.AddOrder(type,source,RobotType::AttackRobot);break;
                        case 49: pCommand.AddOrder(type,source,RobotType::DefenseRobot);break;
                        case 51: pCommand.AddOrder(type,source,RobotType::GatherRobot);break;
                    }
        }
        if(uTargetSkill && isFeedBack)pShowInfo->DeselectGrid();
    }

    //解析按下全局按钮的事件
    void parseGlobalButtonClick(const HumanOrder& order)
    {
        switch (order.id) {
            case 0: if(isFeedBack)pShowInfo->Surrender();
        }
    }

    //解析按键事件
    void parseKeyDown(const HumanOrder& order)
    {
        //技能快捷键
        if (playerInfo.RobotAt(choose) != nullptr) {
            switch (order.id) {
                case 97: type = OrderType::PlainAttack;uTargetSkill=true;break; //A
                case 115: type = OrderType::Split;uTargetSkill=true;break;      //S
                case 99: type = OrderType::Connect;uTargetSkill=true;break;     //C
                case 100: type = OrderType::Disconnect;uTargetSkill=true;break; //D
                case 114: type = OrderType::Recover;uTargetSkill=true;break;    //R
                case 102: type = OrderType::Airborne;uTargetSkill=true;break;   //F
                case 111: pCommand.AddOrder(OrderType::Overload,source);break;  //O
                case 116: type = OrderType::Scourge;uTargetSkill=true;break;    //T
                case 98: type = OrderType::Bombing;uTargetSkill=true;break;     //B
                case 104: pCommand.AddOrder(OrderType::Shielding,source);break; //H
                case 101: pCommand.Evolve(source);break;                        //E
                case 118: pCommand.Vestigial(source);break;                     //V
            }
        }
        if(uTargetSkill && isFeedBack)pShowInfo->DeselectGrid();
    }

    //解析左键点击事件
    void parseLeftMouseClick(const HumanOrder& order)
    {
        //释放单目标点技能
        if(uTargetSkill)
        {
            uTargetSkill=false;
            pCommand.AddOrder(type,source,order.target);
            const Robot* actor = playerInfo.RobotAt(source);
            const Robot* target = playerInfo.RobotAt(order.target);
            if (actor != NULL && target != NULL && type==OrderType::PlainAttack)
                last_target[actor->id] = target->id;
            if(isFeedBack)
                pShowInfo->PosFlash(order.target);
        }
        else Select(order.target);
    }

    //解析右键点击事件
    void parseRightMouseClick(const HumanOrder& order)
    {
        Deselect();
    }

    //解析控制台事件
    void parseConsole(const HumanOrder& order)
    {
        if(order.info == "gg" || order.info == "GG")
            if(isFeedBack)pShowInfo->Surrender();
    }

    void parse(const HumanOrder& order)
    {
        if(isFeedBack)
            log(order);
        switch (order.type)
        {
            case HumanOrderType::Console: parseConsole(order);break;
            case HumanOrderType::KeyDown: parseKeyDown(order);break;
            case HumanOrderType::KeyUp: break;
            case HumanOrderType::LeftMouseDown: break;
            case HumanOrderType::LeftMouseUp: break;
            case HumanOrderType::LeftMouseClick: parseLeftMouseClick(order);break;
            case HumanOrderType::RightMouseClick: parseRightMouseClick(order);break;
            case HumanOrderType::LocalButtonClick: parseLocalButtonClick(order);break;
            case HumanOrderType::GlobalButtonClick: parseGlobalButtonClick(order);break;
        }
    }

    void parse(const vector<HumanOrder>& orders)
    {
        for (unsigned int i = 0; i < orders.size(); i++)
            parse(orders[i]);
    }
}parser;


//稍微智能一点的AI。若之前某单位x手动对某单位y释放技能后，以后每回合x都会向y攻击（x、y仍存在且x无其他手动操作）
//否则自动普通攻击自己攻击范围内血量最少的英雄
class autoAI
{
private:
    void init()
    {
        last_target.clear();
    }

    //按照机器人血量排序
    void sort(vector<Robot*>& robot)
    {
        for (int i = 0; i < robot.size(); ++i)
            for (int j = robot.size() - 1; j > i; --j)
                if (robot[j]->hp < robot[j - 1]->hp)
                {
                    Robot* tmp = robot[j];
                    robot[j] = robot[j - 1];
                    robot[j - 1] = tmp;
                }
    }

    Robot* chooseenemy(const vector<Robot*>& enemyRobot, const Pos& pos, int range) // 在敌人列表中选择一个机器人，使得它与给定位置的距离<range
    {
        for (int i = 0; i < enemyRobot.size(); ++i)
        {
            Robot* ene = enemyRobot[i];
            int dx = pos.x - ene->pos.x;
            int dy = pos.y - ene->pos.y;
            if(dx * dx + dy * dy <= range)
                return ene;
        }
        return NULL;
    }
public:
    void solve()
    {
        if (playerInfo.round == 0)
            init();


        vector<Robot *> MyRobot, EnemyRobot;//我方机器人列表，敌方机器人列表
        vector<Pos> BuildAblePos;//当前地图上的空地
        //构造MyRobot, EnemyRobot
        for (unsigned int i = 0; i < playerInfo.robots.size(); i++) {
            Robot &obj = playerInfo.robots[i];
            if (obj.team == playerInfo.team)
                MyRobot.push_back(&obj);
            else
                EnemyRobot.push_back(&obj);
        }

        for (int x = 0; x < MAP_SIZE; x++)
            for (int y = 0; y < MAP_SIZE; y++)
                if (MAP[x][y] == 1 && playerInfo.RobotAt(Pos(x, y)) == NULL)
                    BuildAblePos.push_back(Pos(x, y));

        //敌方机器人按照其剩余血量升序排列
        sort(EnemyRobot);

        for (int i = 0; i < MyRobot.size(); ++i)
        {
            Robot* robot = MyRobot[i];
            string id = robot->id;
            std::map<string, string>::iterator it = last_target.find(id);
            if (it != last_target.end())
            {
                const Robot* enemy = playerInfo.RobotNamed(it->second);
                if (enemy != NULL)
                    pCommand.AddOrder(OrderType::PlainAttack, robot->pos, enemy->pos);
                else last_target.erase(it);
                continue;
            }

            Robot* enemy = chooseenemy(EnemyRobot, robot->pos, robot->attack_range);
            if (enemy == NULL) continue;
            pCommand.AddOrder(OrderType::PlainAttack, robot->pos, enemy->pos);
        }
    }
}autoai;


//普通AI接口，一回合调用一次
extern "C"
{
__declspec(dllexport) void player_ai(const PlayerInfo &playerInfo_, Commands &pCommand_, PShowInfo &pShowInfo_) {
        //这里将输入的PlayerInfo转化为PPlayerInfo格式
        playerInfo = SDK::interpretPlayerInfo(playerInfo_);

        pShowInfo = &pShowInfo_;
        parser.isFeedBack = false;
        parser.parse(playerInfo.orders);
        autoai.solve();
        
        //能量传输
        std::map<Pos, int> needs, weights;
        needs.clear(); weights.clear();
        for (auto i: pCommand.cmds) {
            const Robot *robot = playerInfo.RobotAt(i.source);
            if (robot == nullptr) continue;
            int cost = PPlayerInfo::Robot::Skill::Cost(SkillType(int(i.type)), robot->level, robot->type);
            needs[robot->pos] += cost;
            pCommand.AddAutoTransfer(playerInfo, weights, needs);
        }
        
        //这里将PCommands格式转化为Commands格式输出
        pCommand_ = SDK::translateCommands(playerInfo, pCommand);
        pCommand.cmds.clear();

        return;
    }
    //高速AI接口，播放器一帧调用一次
__declspec(dllexport) void feedback_ai(vector<HumanOrder> orders, PShowInfo &pShowInfo_) {
        //在这里进行一些处理
        parser.isFeedBack = true;
        pShowInfo = &pShowInfo_;
        parser.parse(orders);
        return;
    }
}
